<?php

namespace app\common\service;

use app\event\MovieNotifySuccess;
use app\model\MovieOrder;
use app\model\TaototoFilm;
use think\facade\Db;
use app\common\model\FinanceStat;
use think\facade\Log;

/**
 * 守兔影票.
 */
class Taototo
{
    private $id;
    private $url;
    private $appkey;
    private $secret;
    private $error;

    public function __construct()
    {
        $supplier = \app\model\BaseSupplier::where(['code' => 'taototo'])->find();
        if (empty($supplier)) {
            throw new \think\Exception('电影账号未配置');
        }

        try {
            $this->id = $supplier['id'];
            $this->url = rtrim($supplier['api_config']['url'], '/');
            $this->appkey = $supplier['api_config']['appkey'];
            $this->secret = $supplier['api_config']['secret'];
        } catch (\Exception $e) {
            throw new \think\Exception($e->getMessage());
        }
    }

    public function getId()
    {
        return $this->id;
    }

    /**
     * 一级城市列表.
     */
    public function getCityList()
    {
        $url = $this->url . '/movieapi/movie-info/get-city-list';
        $params = $this->getFormatParams([]);

        return $this->curlPost($url, $params);
    }

    /**
     * 二级城市
     */
    public function getCityArea($cityId = 0)
    {
        $url = $this->url . '/movieapi/movie-info/get-city-area';
        $params = $this->getFormatParams([
            'cityId' => $cityId,
        ]);

        return $this->curlPost($url, $params);
    }

    /**
     * 正在热映.
     */
    public function getHotList($cityId = 0)
    {
        $now = time();
        $list = TaototoFilm::query()
            ->where('city_id', $cityId)
            ->where('show_status', 1)
            ->where('expire_at', '>', $now)
            ->select();
//            ->toArray();
        if (!$list->isEmpty()) {
            return $list;
        }

        $url = $this->url . '/movieapi/movie-info/get-hot-list';
        $params = $this->getFormatParams([
            'cityId' => $cityId,
        ]);
        $list = $this->curlPost($url, $params);
        $list = json_decode($list, true);
        if (empty($list['data']['list'])) {
            return [];
        }
        $list = $list['data']['list'];
//        Log::info($list);
        $insert = [];
        $expire_at = strtotime(date('Y-m-d 23:59:59'));

        $obj = new TaototoFilm();

        foreach ($list as $v) {
            $insert[] = [
                'city_id' => $cityId,
                'cast' => $v['cast']??'',
                'director' => $v['director']??'',
                'duration' => $v['duration']??0,
                'film_id' => $v['filmId'],
                'film_types' => $v['filmTypes']??'',
                'grade' => $v['grade'],
                'intro' => $v['intro'] ?? '',
                'language' => $v['language']??'',
                'like_num' => $v['likeNum'],
                'name' => $v['name'],
                'pic' =>$obj->getPicAttr($v['pic']) ,
                'publish_date' => $v['publishDate'],
                'show_status' => 1,
                'version_types' => $v['versionTypes']??'',
                'expire_at' => $expire_at,
            ];
        }
        unset($list);

        Db::startTrans();
        try {
            Db::name('taototo_film')
                ->where('city_id', $cityId)
                ->where('show_status', 1)
                ->delete();
            if ($insert) {
                Db::name('taototo_film')->insertAll($insert);
            }

            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            $this->error = '获取失败：' . $e->getMessage();
            Log::error($this->error);
            return false;
        }

        return $insert;
    }

    /**
     * 即将上映.
     */
    public function getSoonList($cityId = 0)
    {
        $now = time();
        $list = Db::name('taototo_film')
            ->where('city_id', $cityId)
            ->where('show_status', 2)
            ->where('expire_at', '>', $now)
            ->select()
            ->toArray();
        if (!empty($list)) {
            return $list;
        }

        $url = $this->url . '/movieapi/movie-info/get-soon-list';
        $params = $this->getFormatParams([
            'cityId' => $cityId,
        ]);

        $list = $this->curlPost($url, $params);
        $list = json_decode($list, true);
        if (empty($list['data']['list'])) {
            return [];
        }
        $list = $list['data']['list'];
        $insert = [];
        $expire_at = strtotime(date('Y-m-d 23:59:59'));
        foreach ($list as $v) {
            $insert[] = [
                'city_id' => $cityId,
                'cast' => $v['cast']??'',
                'director' => $v['director']??'',
                'duration' => $v['duration']??0,
                'film_id' => $v['filmId'],
                'film_types' => $v['filmTypes']??'',
                'grade' => $v['grade'],
                'intro' => $v['intro'] ?? '',
                'language' => $v['language']??'',
                'like_num' => $v['likeNum'],
                'name' => $v['name'],
                'pic' => $v['pic'],
                'publish_date' => $v['publishDate'],
                'show_status' => 2,
                'version_types' => $v['versionTypes']??'',
                'expire_at' => $expire_at,
            ];
        }
        unset($list);

        Db::startTrans();
        try {
            Db::name('taototo_film')
                ->where('city_id', $cityId)
                ->where('show_status', 2)
                ->delete();
            if ($insert) {
                Db::name('taototo_film')->insertAll($insert);
            }

            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            $this->error = '获取失败：' . $e->getMessage();
            Log::error($this->error);
            return false;
        }

        return $insert;
    }

    /**
     * 影院列表.
     */
    public function getCinemaList($cityId = 0)
    {
        $url = $this->url . '/movieapi/movie-info/get-cinema-list';
        $params = $this->getFormatParams([
            'cityId' => $cityId,
        ]);

        $result = $this->curlPost($url, $params);
        $attr = json_decode($result, true);
        if (!isset($attr['data']['list'])) {
            return false;
        }

        return $attr['data']['list'];
    }

    /**
     * 影院的场次排期
     */
    public function getScheduleList($params)
    {
        $cinemaId = $params['cinemaId'];
        // 看看数据库有没有数据，有的话直接返回
        $now = time();
        $cinema = Db::name('taototo_cinema')
            ->where('cinema_id', $cinemaId)
            ->find();
        $where = [
            'cinema_id' => $cinemaId,
        ];
        if (!empty($params['filmId'])) {
            $where['film_id'] = $params['filmId'];
            unset($params['filmId']);
        }
        if (!empty($params['showDate'])) {
            $where['show_date'] = $params['showDate'];
            unset($params['showDate']);
        }
        if (!empty($cinema) && $cinema['expire_at'] > $now) {
            $list = Db::name('taototo_schedule')
                ->where($where)
                ->select();

            return [
                // 'down_discount_rate' => $cinema['down_discount_rate'],
                'discount_rate' => strval($cinema['down_discount_rate']),
                // 'up_discount_rate' => $cinema['up_discount_rate'],
                'list' => $list,
            ];
        }

        $url = $this->url . '/movieapi/movie-info/get-schedule-list';
        $params = $this->getFormatParams([
            'cinemaId' => $cinemaId,
        ]);

        $res = $this->curlPost($url, $params);
        $res = json_decode($res, true);
        if (!isset($res['code']) || 200 != $res['code']) {
            $this->error = '数据获取失败: ' . json_encode($res, JSON_UNESCAPED_UNICODE);

            return false;
        }

        $cinemaUpdate = [
            'cinema_id' => $cinemaId,
            'down_discount_rate' => $res['data']['discountRule']['downDiscountRate'],
            'up_discount_rate' => $res['data']['discountRule']['upDiscountRate'],
            'expire_at' => $now + 3600, // 缓存一个小时
        ];
        $list = [];
        foreach ($res['data']['list'] as $v) {
            $list[] = [
                'cinema_id' => $v['cinemaId'],
                'cinema_name' => $v['cinemaName'],
                'duration' => $v['duration'],
                'film_id' => $v['filmId'],
                'film_name' => $v['filmName'],
                'hall_name' => $v['hallName'],
                'language' => $v['language'],
                'net_price' => $v['netPrice'],
                'plan_type' => $v['planType'],
                'schedule_area' => $v['scheduleArea'],
                'show_date' => $v['showDate'],
                'show_id' => $v['showId'],
                'show_time' => $v['showTime'],
                'end_time' => date('Y-m-d H:i:s', strtotime($v['showTime']) + $v['duration'] * 60),
                'show_version_type' => $v['showVersionType'],
                'stop_sell_time' => $v['stopSellTime'],
                'down_discount_rate' => $cinemaUpdate['down_discount_rate'],
                'up_discount_rate' => $cinemaUpdate['up_discount_rate'],
            ];
        }
        unset($res);
        Db::startTrans();
        try {
            if ($cinema) {
                Db::name('taototo_cinema')
                    ->where('id', $cinema['id'])
                    ->update($cinemaUpdate);
            } else {
                Db::name('taototo_cinema')
                    ->insert($cinemaUpdate);
            }
            Db::name('taototo_schedule')
                ->where('cinema_id', $cinemaId)
                ->delete();
            if ($list) {
                Db::name('taototo_schedule')->insertAll($list);
                unset($list);
            }

            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            $this->error = '获取失败：' . $e->getMessage();

            return false;
        }

        $list = Db::name('taototo_schedule')
            ->where($where)
            ->select();

        return [
            'discount_rate' => strval($cinemaUpdate['down_discount_rate']),
            // 'up_discount_rate' => $cinemaUpdate['up_discount_rate'],
            'list' => $list,
        ];
    }

    /**
     * 场次座位.
     */
    public function getSeat($showId = 0)
    {
        $url = $this->url . '/movieapi/movie-info/get-seat';
        $params = $this->getFormatParams([
            'showId' => $showId,
        ]);

        $list = $this->curlPost($url, $params);
        $list = json_decode($list, true);
        if (200 !== $list['code']) {
            $this->error = $list['message'];

            return false;
        }

        return $list['data']['seatData'] ?? [];
    }

    /**
     * 包含某电影的影院.
     */
    public function getShowList($params = [])
    {
        $url = $this->url . '/movieapi/movie-info/get-show-list';
        $params = $this->getFormatParams($params);

        $res = $this->curlPost($url, $params);
        $res = json_decode($res, true);
        if (200 != $res['code']) {
            $this->error = $res['message'];
            return false;
        }

        return $res['data'];
    }

    /**
     * 包含某电影的日期
     */
    public function getShowDate($params = [])
    {
        $url = $this->url . '/movieapi/movie-info/get-show-date';
        $params = $this->getFormatParams($params);

        return $this->curlPost($url, $params);
    }

    /**
     * 下单.
     */
    public function orderCreate($params = [])
    {
        $url = $this->url . '/api/order/create';
        $params = $this->getFormatParams($params);

        return $this->curlPost($url, $params);
    }

    /**
     * 回调流程主动触发 测试用.
     */
    public function orderHandle($params)
    {
        $url = $this->url . '/api/automation/orderHandle';
        $url = str_replace('movieapi2', 'movieapi', $url);
        $params = $this->getFormatParams($params);

        return $this->curlPost($url, $params);
    }

    /**
     * 订单查询.
     */
    public function orderQuery($params)
    {
        $url = $this->url . '/api/order/query';
        $params = $this->getFormatParams($params);

        return $this->curlPost($url, $params);
    }

    /**
     * 账号信息查询.
     */
    public function userInfo()
    {
        $url = $this->url . '/api/user/info';
        $params = $this->getFormatParams([]);

        return $this->curlPost($url, $params);
    }

    /**
     * 秒出单下单.
     */
    public function createSoonOrder($params)
    {
        $url = $this->url . '/api/order/create-soon-order';
        $params = $this->getFormatParams($params);

        return $this->curlPost($url, $params);
    }

    /**
     * 请求参数统一处理.
     */
    public function getFormatParams($params = [])
    {
        $params['appKey'] = $this->appkey;
        $params['time'] = time();
        $params['sign'] = $this->getSign($params);

        return $params;
    }

    /**
     * 生成签名.
     */
    private function getSign($params)
    {
        ksort($params);
        $str = '';
        foreach ($params as $k => $v) {
            $str .= $k . '=' . $v . '&';
        }
        $str .= 'appSecret=' . $this->secret;

        return md5($str);
    }

    /**
     * CURL POST.
     */
    public function curlPost($url, $data = [], $header = [])
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

        if (empty($header)) {
            $header = [
                'Content-Type:application/x-www-form-urlencoded',
            ];
        }
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        $output = curl_exec($ch);
        curl_close($ch);

        return $output;
    }

    /**
     * 获取错误信息.
     */
    public function getError()
    {
        return $this->error;
    }

    /**
     * 获取不同区域价格
     *
     * 示例：area:1,price:3690,serviceFee:300;area:227,price:3690,serviceFee:300;area:228,price:3690,serviceFee:300
     */
    public function getScheduleAreaPriceArr($str)
    {
        if (empty($str)) {
            return [];
        }
        $arr = explode(';', $str);
        $arr = array_map(function ($val) {
            return explode(',', $val);
        }, $arr);

        $scheduleArea = [];
        foreach ($arr as $k1 => $v1) {
            foreach ($v1 as $k2 => $v2) {
                $v2 = explode(':', $v2);
                $scheduleArea[$k1][$v2[0]] = $v2[1];
            }
        }
        $scheduleArea = array_column($scheduleArea, null, 'area');

        return $scheduleArea;
    }

    /**
     * 订单回调处理.
     */
    public function notify($params)
    {
        $result = [
            'success' => false,
            'message' => '处理失败',
            'code' => 1024,
        ];

        $fields = [
            'sign', 'appKey', 'time', 'eventName', 'thirdOrderId',
        ];
        foreach ($fields as $key) {
            if (!isset($params[$key])) {
                $result['message'] = '缺少参数【' . $key . '】';

                return json($result);
            }
        }
//        $order = Db::name('movie_order')
//            ->where('order_id', $params['thirdOrderId'])
//            ->find();
        $movie_order = MovieOrder::query()->where('order_id', $params['thirdOrderId'])->findOrEmpty();
        $old_movie_order = clone $movie_order;
        $order = $movie_order->toArray();
        if (empty($order)) {
            $result['message'] = '订单没找到';

            return json($result);
        }

        $sign = $params['sign'];
        unset($params['sign']);
        if ($sign != $this->getSign($params)) {
            $result['message'] = '验签失败';

            return json($result);
        }

        $notifyData = null;
        switch ($params['eventName']) {
            case 'ORDER_CLOSE': // 订单因为某种原因，关闭，或出票失败，或场次取消等，通知接入方。此时接入方应开启退款流程
                $orderUpdate = [
                    'supplier_status' => 10,
                    'close_time' => time(),
                    'close_cause' => $params['closeCause'],
                    'refund_status' => 2,
                ];
                $notifyData = [
                    'status' => 10,
                    'close_cause' => $params['closeCause'],
                ];
                break;
            case 'ORDER_FINISH': // 当订单正常处理完毕后回调。 表明此订单处理结束，包括已结算
                $orderUpdate = [
                    'finish_time' => time(),
                    'supplier_status' => 5,
                    'settle_status' => 2,
                ];
                break;
            case 'WAIT_TICKET': // 订单竞价结束，正在等待出票时，回调
                $totalProfit = $order['sale_price'] - $params['orderPrice'];
                $agentProfit = intval(strval($totalProfit * $order['commission_rate'] / 100));
                $platformProfit = $totalProfit - $agentProfit;
                $orderUpdate = [
                    'supplier_status' => 3,
                    'supplier_price' => $params['orderPrice'],
                    'profit' => $agentProfit,
                    'platform_profit' => $platformProfit,
                ];
                break;
            case 'TICKET_SUCCESS': // 订单出票成功时候回调， 参数包含出票相关信息。
            case 'TICKET_SYNC': // 	当取票码出现意外情况，需要修改时，回调第三方。 参数与 TICKET_SUCCESS 一致。
                $orderUpdate = [
                    'supplier_status' => 4,
                    'real_seat' => $params['realSeat'] ?? '',
                    'ticket_code' => $params['ticketCode'] ?? '[]',
                    'ticket_image' => $params['ticketImage'] ?? '[]',
                ];
                $notifyData = [
                    'status' => 4,
                    'settle_price' => $order['sale_price'] - $order['profit'],
                    'real_seat' => $params['realSeat'] ?? '',
                    'ticket_code' => $params['ticketCode'] ?? '[]',
                    'ticket_image' => $params['ticketImage'] ?? '[]',
                ];
                break;
            default:
                $result['message'] = '回调事件有误';

                return json($result);
                break;
        }

        Db::startTrans();
        try {
            Db::name('movie_order')
                ->where('id', $order['id'])
                ->update($orderUpdate);
            if (!empty($order['notify_url']) && $notifyData) {
                $agent = Db::name('agent')
                    ->field('app_key, app_secret')
                    ->where('id', $order['agent_id'])
                    ->find();
                $notifyData = array_merge($notifyData, [
                    'order_id' => strval($order['order_id']),
                    'out_order_id' => $order['out_order_id'],
                    'app_key' => $agent['app_key'],
                    'app_secret' => $agent['app_secret'],
                ]);
                Db::name('movie_notify_agent')
                    ->insert([
                        'order_id' => $order['order_id'],
                        'notify_url' => $order['notify_url'],
                        'params' => json_encode($notifyData),
                        'status' => 1,
                        'send_time' => time(),
                        'result' => '',
                    ]);
            }
            Db::commit();
//            //TODO 1.movie_order更新成功 2.更新前ticket_code和ticket_image为空，3.更新时候ticket_image和ticket_image不为空
//            //TODO 触发发生短信
//            /**
//             * @var MovieOrder $movie_order
//             * @var MovieOrder $old_movie_order
//             */
//            $old_ticket_code = json_decode($old_movie_order->ticket_code,true);
//            $old_ticket_image = json_decode($old_movie_order->ticket_image,true);
//            $new_ticket_code =  json_decode($orderUpdate['ticket_code'],true);
//            $new_ticket_image =  json_decode($orderUpdate['ticket_image'],true);
//            if ((empty($old_ticket_code) && empty($old_ticket_image)) && (!empty($new_ticket_code) && !empty($new_ticket_image))) {
//                event(new MovieNotifySuccess($movie_order));
//            }
        } catch (\Exception $e) {
            Db::rollback();

            return json([
                'success' => false,
                'message' => '请求失败' . $e->getMessage(),
                'code' => 2048,
            ]);
        }

        return json([
            'success' => true,
            'message' => '请求成功',
            'code' => 200,
        ]);
    }
}
